import {
  createAiReplaceBackground,
  CreateAiReplaceBackgroundOptions,
  createProject,
  getImageMask,
  getUploadImageInfo,
  identify,
  queryCreateAiReplaceBackground,
  QueryCreateAiReplaceBackgroundOptions,
  uploadImageToCos,
} from '@/api/meituxiuxiu';
import { BackgroundReference, State } from '@/store';
import { getFileName, getPixelDataFromImage, getRandomElement, getRandomNumber } from './utils';

export async function uploadImage(imageBlob: Blob, filename = '') {
  const uploadImageInfoResult = await getUploadImageInfo();
  const uploadImageInfo = uploadImageInfoResult[0];
  // console.log('获取到图片上传信息', uploadImageInfo);
  const uploadImageResult = await uploadImageToCos({
    token: uploadImageInfo.mtyun.token,
    file: imageBlob,
    key: uploadImageInfo.mtyun.key,
    fname: filename,
  });
  // console.log('图片上传结果', uploadImageResult);
  return uploadImageResult.data;
}

export async function changeImageBackground(
  sourceImage: File,
  processSettings: State['processSettings'],
) {
  // 源图片地址
  const imageUrl = await uploadImage(sourceImage, sourceImage.name);
  // console.log(imageUrl);

  const cookies = await browser.cookies.getAll({
    url: 'https://www.designkit.com/',
  });
  const gid = cookies.find((cookie) => cookie.name === '_sm')?.value || '';
  const client_id = cookies.find((cookie) => cookie.name === '__mt_web_client_id__')?.value || '';
  const user_identity = cookies.find((cookie) => cookie.name === 'user_identity')?.value || '';
  // console.log(user_identity);
  let oid = 663251843;
  let groupId = 663251843;
  try {
    const userIdentity = JSON.parse(user_identity.replaceAll('%22', '"').replaceAll('%2C', ','));
    oid = userIdentity.oid;
    groupId = userIdentity.groupId;
  } catch (error) {
    console.log(error);
  }

  // 获取图片的分类
  const identifyResult = await identify({
    gid,
    client_id,
    url: imageUrl,
  });
  if (identifyResult.code !== 0) {
    throw new Error('获取图片的分类失败: ' + identifyResult.message);
  }
  const category_id = identifyResult.data.category_id;
  const product_category = identifyResult.data.product_category;
  // console.log(category_id, product_category);

  // 获取抠图使用的模版

  // console.log(gid, client_id);
  const getImageMaskResult = await getImageMask({
    source: imageUrl,
    client_id: client_id,
    gid: gid,
  });
  if (getImageMaskResult.code !== 0) {
    throw new Error('获取抠图模版失败');
  }
  // 抠图后的模版文件地址
  const maskUrl = getImageMaskResult.data.media_info_list[0].media_data;
  // 获取经过抠图和比例调整后的图像
  const { maskRect, maskRatioRect, maskRatioBlob } = await processMask(
    sourceImage,
    maskUrl,
    processSettings.maskRatio,
  );
  // console.log(maskUrl);

  // 创建项目 id
  const createProjectResult = await createProject({
    client_id,
    gid,
    name: getFileName(sourceImage.name),
    imageUrl,
    category_id,
    product_category,
    maskUrl,
  });
  if (createProjectResult.code !== 0) {
    throw new Error('创建项目 id 失败: ' + createProjectResult.message);
  }
  const projectID = createProjectResult.data.project_id;

  // console.log(projectID);

  // 随机挑一个背景参考
  const backgroundReference = getRandomElement<BackgroundReference>(
    processSettings.backgroundReferenceList,
  );
  if (!backgroundReference) {
    throw new Error('至少需要设置一个背景参考');
  }
  const refimage_blob = await (await fetch(backgroundReference.dataUrl)).blob();
  const refimage_url = await uploadImage(refimage_blob);

  const createAiReplaceBackgroundOptions: CreateAiReplaceBackgroundOptions = {
    client_id,
    gid,
    prompt_vs_refimage: getRandomNumber(
      processSettings.aiTendency.min,
      processSettings.aiTendency.max,
    ),
    guidance_scale: getRandomNumber(processSettings.aiCreative.min, processSettings.aiCreative.max),
    steps: getRandomNumber(processSettings.aiSamplingStep.min, processSettings.aiSamplingStep.max),
    job_name: getFileName(sourceImage.name),
    box1: [maskRect.xMin, maskRect.yMin, maskRect.w, maskRect.h].join(','),
    box2: [
      maskRatioRect.xMin / 2,
      maskRatioRect.yMin / 2,
      maskRatioRect.w / 2,
      maskRatioRect.h / 2,
    ].join(','),
    mask_url: maskUrl,
    url: imageUrl,
    category_id: category_id,
    product_category: product_category,
    projectID: projectID,
    refimage_url: refimage_url,
    clientOgroupid: groupId,
    clientOid: oid,
  };

  // const maskRatioBUrl = await uploadImage(maskRatioBlob);
  // console.log(maskRatioBUrl)
  // console.log('创建替换背景时的接口参数', createAiReplaceBackgroundOptions);
  // throw new Error('未实现');

  // return 'https://xiuxiu-pro.meitudata.com/ai_product_result/6815a35e321338049ZjbD0JEvQ5981.jpeg';
  // 正式发起替换背景的请求
  const createAiReplaceBackgroundResult = await createAiReplaceBackground(
    createAiReplaceBackgroundOptions,
  );
  // console.log('创建替换背景结果', createAiReplaceBackgroundResult);
  if (createAiReplaceBackgroundResult.code !== 0) {
    throw new Error(`替换背景失败: ${createAiReplaceBackgroundResult.message}`);
  }
  // 轮询获取生成结果
  const resultUrl = await query(
    {
      client_id,
      gid,
      id: createAiReplaceBackgroundResult.data.commerce_task_id,
      alg_task_id: createAiReplaceBackgroundResult.data.id,
      clientOgroupid: groupId,
      clientOid: oid,
    },
    processSettings.aiProcessTimeout,
  );
  return resultUrl;
}

export async function processMask(
  sourceImage: File,
  maskUrl: string,
  maskRatio: {
    min: number;
    max: number;
  },
) {
  // 读取图像的数据
  const maskImageData = await getPixelDataFromImage(maskUrl);
  // console.log(imageData);
  const maskRect = getNonTransparentBounds(maskImageData);
  if (!maskRect) {
    throw new Error('无法获取抠图模版中的抠图区域');
  }
  const sourceImageData = await getPixelDataFromImage(sourceImage);
  // 融合抠图模版和原始图像,获取抠图后的图像
  const mergedImageData = mergeMaskAndSourceImage(sourceImageData, maskImageData);
  const maskRatioBlob = await fitMaskRectToFullImageKeepAspectRatio(
    mergedImageData,
    maskRect,
    maskRatio,
  );
  const maskRatioImageData = await getPixelDataFromImage(maskRatioBlob);
  const maskRatioRect = getNonTransparentBounds(maskRatioImageData);
  if (!maskRatioRect) {
    throw new Error('无法获取调整比例后的抠图区域');
  }
  return {
    maskRatioBlob,
    maskRect,
    maskRatioRect,
  };
}

export function getNonTransparentBounds(
  imageData: ImageData,
): { xMin: number; yMin: number; xMax: number; yMax: number; w: number; h: number } | null {
  const data = imageData.data;
  const width = imageData.width;
  const height = imageData.height;

  let xMin = width,
    yMin = height,
    xMax = -1,
    yMax = -1;

  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const index = (y * width + x) * 4;
      const alpha = data[index + 3]; // 获取 alpha 通道值 [0, 255]

      if (alpha > 0) {
        // 如果不是完全透明
        if (x < xMin) xMin = x;
        if (x > xMax) xMax = x;
        if (y < yMin) yMin = y;
        if (y > yMax) yMax = y;
      }
    }
  }

  // 如果没有找到任何不透明像素
  if (xMax === -1 || yMax === -1) return null;

  return { xMin, yMin, xMax, yMax, w: xMax - xMin + 1, h: yMax - yMin + 1 };
}

export function mergeMaskAndSourceImage(
  sourceImageData: ImageData,
  maskImageData: ImageData,
): ImageData {
  const width = maskImageData.width;
  const height = maskImageData.height;
  const mergedImageData = new ImageData(width, height);
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const index = (y * width + x) * 4;
      const alpha = maskImageData.data[index + 3]; // 获取 alpha 通道值 [0, 255]
      if (alpha > 0) {
        mergedImageData.data[index] = sourceImageData.data[index];
        mergedImageData.data[index + 1] = sourceImageData.data[index + 1];
        mergedImageData.data[index + 2] = sourceImageData.data[index + 2];
        mergedImageData.data[index + 3] = alpha;
      } else {
        mergedImageData.data[index] = 0;
        mergedImageData.data[index + 1] = 0;
        mergedImageData.data[index + 2] = 0;
        mergedImageData.data[index + 3] = 0;
      }
    }
  }
  return mergedImageData;
}

export async function fitMaskRectToFullImageKeepAspectRatio(
  imageData: ImageData,
  maskRect: { xMin: number; yMin: number; xMax: number; yMax: number },
  maskRatio: {
    min: number;
    max: number;
  },
) {
  const { xMin, yMin, xMax, yMax } = maskRect;
  const sourceWidth = xMax - xMin + 1;
  const sourceHeight = yMax - yMin + 1;
  const targetWidth = imageData.width;
  const targetHeight = imageData.height;

  // 创建源 canvas 并绘制裁剪区域
  const sourceCanvas = new OffscreenCanvas(sourceWidth, sourceHeight);
  const sourceCtx = sourceCanvas.getContext('2d')!;
  // console.log(xMin, yMin, sourceWidth, sourceHeight);
  sourceCtx.putImageData(imageData, -xMin, -yMin, xMin, yMin, sourceWidth, sourceHeight);

  // 创建目标 canvas
  const destCanvas = new OffscreenCanvas(targetWidth, targetHeight);
  const destCtx = destCanvas.getContext('2d')!;

  // 计算缩放比例和位置（保持比例）
  const ratio = Math.min(targetWidth / sourceWidth, targetHeight / sourceHeight);
  // 随机生成比例
  const randomRatio = getRandomNumber(maskRatio.min, maskRatio.max);
  // console.log(randomRatio);
  const scaledWidth = sourceWidth * ratio * randomRatio;
  const scaledHeight = sourceHeight * ratio * randomRatio;
  const dx = (targetWidth - scaledWidth) / 2;
  const dy = (targetHeight - scaledHeight) / 2;

  // 绘制缩放后的图像
  destCtx.drawImage(
    sourceCanvas,
    0,
    0,
    sourceWidth,
    sourceHeight,
    dx,
    dy,
    scaledWidth,
    scaledHeight,
  );

  // 获取新的 ImageData
  return await destCanvas.convertToBlob({
    type: 'image/png',
  });
}

// 渲染 ImageData
export async function renderImageData(imageData: ImageData) {
  const canvas = new OffscreenCanvas(imageData.width, imageData.height);
  const ctx = canvas.getContext('2d')!;
  ctx.imageSmoothingEnabled = true;
  ctx.imageSmoothingQuality = 'high';
  ctx.putImageData(imageData, 0, 0);
  const blob = await canvas.convertToBlob();
  const url = await uploadImage(blob, '');
  console.log(url);
  // return canvas;
}

// 轮询结果
export async function query(
  queryCreateAiReplaceBackgroundOptions: QueryCreateAiReplaceBackgroundOptions,
  aiProcessTimeout: number,
): Promise<string> {
  return new Promise((resolve, reject) => {
    const timer = setInterval(async () => {
      const queryResult = await queryCreateAiReplaceBackground(
        queryCreateAiReplaceBackgroundOptions,
      );
      if (queryResult.code !== 0) {
        reject(new Error('获取替换背景的图片失败:  ' + queryResult.message));
        clearInterval(timer);
      } else {
        // 只要有一个状态是 2 而且有 result_url 就返回
        const taskCompeleted = queryResult.data.subtasks.filter((task) => {
          return task.process_status === 2 && task.result_url;
        });
        if (taskCompeleted.length > 0) {
          const targetTaskResult = getRandomElement(taskCompeleted);
          resolve(targetTaskResult!.result_url);
          clearInterval(timer);
        }
      }
    }, 1000);
    setTimeout(() => {
      reject(new Error('获取替换背景的图片超时'));
      clearInterval(timer);
    }, 1000 * aiProcessTimeout);
  });
}

// 添加图片水印
export async function addImageWaterMark(sourceFile: Blob, watermarkBlob: Blob) {
  // 加载源图像和水印图像
  const sourceImage = await createImageBitmap(sourceFile);
  const watermarkImage = await createImageBitmap(watermarkBlob);

  const canvas = new OffscreenCanvas(sourceImage.width, sourceImage.height);
  const ctx = canvas.getContext('2d')!;

  // 绘制原始图像
  ctx.drawImage(sourceImage, 0, 0);

  // 计算水印尺寸（占原图 25%）
  const watermarkWidth = sourceImage.width * 0.5;
  const watermarkHeight = (watermarkImage.height / watermarkImage.width) * watermarkWidth;

  // 计算水印位置（居中）
  const x = (sourceImage.width - watermarkWidth) / 2;
  const y = (sourceImage.height - watermarkHeight) / 2;

  // 设置透明度（3%）
  ctx.globalAlpha = 0.03;

  // 绘制水印
  ctx.drawImage(watermarkImage, x, y, watermarkWidth, watermarkHeight);

  // 恢复透明度设置
  ctx.globalAlpha = 1.0;

  // 将结果转换为 Blob
  return await canvas.convertToBlob({ type: sourceFile.type, quality: 1 });
}

// 创建拼接图
export async function createSpliceImage(
  files: File[],
  processSettings: State['processSettings'],
): Promise<Blob> {
  const { spliceMargin: margin, spliceGap: gap, spliceRadiu: borderRadius } = processSettings;

  if (files.length !== 4) {
    throw new Error('必须提供四张图片进行拼接');
  }

  const canvasWidth = 800;
  const canvasHeight = 800;

  const imgWidth = (canvasWidth - margin * 2 - gap) / 2;
  const imgHeight = (canvasHeight - margin * 2 - gap) / 2;

  // 加载所有图片为 ImageBitmap
  const images = await Promise.all(files.map((file) => createImageBitmap(file)));
  const [img1, img2, img3, img4] = images;

  const canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
  const ctx = canvas.getContext('2d')!;

  // 填充背景
  const spliceBackgroundReference = getRandomElement(processSettings.spliceBackgroundReferenceList);
  if (spliceBackgroundReference) {
    const backgroundUrl = spliceBackgroundReference.dataUrl;
    const backgroundUrlBlob = await (await fetch(backgroundUrl)).blob();
    // const
    ctx.drawImage(await createImageBitmap(backgroundUrlBlob), 0, 0, canvasWidth, canvasHeight);
  }

  // 绘制 topLeft 图片
  drawRoundedImage(ctx, img1, margin, margin, imgWidth, imgHeight, borderRadius);

  // 绘制 topRight 图片
  drawRoundedImage(ctx, img2, margin + imgWidth + gap, margin, imgWidth, imgHeight, borderRadius);

  // 绘制 bottomLeft 图片
  drawRoundedImage(ctx, img3, margin, margin + imgHeight + gap, imgWidth, imgHeight, borderRadius);

  // 绘制 bottomRight 图片
  drawRoundedImage(
    ctx,
    img4,
    margin + imgWidth + gap,
    margin + imgHeight + gap,
    imgWidth,
    imgHeight,
    borderRadius,
  );

  return await canvas.convertToBlob({ type: files[0].type, quality: 1 });
}

function drawRoundedImage(
  ctx: OffscreenCanvasRenderingContext2D,
  image: ImageBitmap,
  x: number,
  y: number,
  width: number,
  height: number,
  radius: number,
) {
  ctx.save();
  roundRect(ctx, x, y, width, height, radius);
  ctx.clip();
  ctx.drawImage(image, x, y, width, height);
  ctx.restore();
}

// 圆角矩形路径
function roundRect(
  ctx: OffscreenCanvasRenderingContext2D,
  x: number,
  y: number,
  width: number,
  height: number,
  radius: number,
) {
  ctx.beginPath();
  ctx.moveTo(x + radius, y);
  ctx.lineTo(x + width - radius, y);
  ctx.arcTo(x + width, y, x + width, y + radius, radius);
  ctx.lineTo(x + width, y + height - radius);
  ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius);
  ctx.lineTo(x + radius, y + height);
  ctx.arcTo(x, y + height, x, y + height - radius, radius);
  ctx.lineTo(x, y + radius);
  ctx.arcTo(x, y, x + radius, y, radius);
  ctx.closePath();
}
